Node.js语言编程
第一部分 介绍NODE.JS
介绍JS和NODE的特性
介绍基本的NODE.JS编程概念
完整演示如何从头开始待见一个Web程序
第二部分 介绍用node进行web开发
前端构建系统webpack,gulp
node中的服务器框架
Connect和Express
模板语言
数据库
测试
部署、云部署
第三部分 介绍node开发的其他方面
介绍node搭建命令行
Electron开发
第一部分
NODE.JS基础知识
node.js是一个JavaScript运行平台,它的显著特征是它的异步和事件驱动机制,以及小巧精悍的标准库。目前有两个版本LST以及当前版。
node.js和JavaScript的优势之一就是单线程编程模型。多线程一般会引入bug。
非阻塞IO:程序执行过程中,I/O操作不会阻塞程序的执行,也就是在I/O操作的同时,继续执行其他代码,当I/O操作完成时运行一个回调函数来处理这个操作的结果。
npm要求每个node项目目录下都有一个package.json文件,创建package.json最简单的命令是
npm init -y
,这样就会生成简单的JSON格式的项目描述信息。用带参数npm install --save
来安装包就会自动更新package.json文件。node自带了很多实用的库,统称为核心模块。也就是相当于其他语言的标准库,是编写服务端JS所需的工具。
node中核心库主要有:文件系统库(fs、path),TCP客户端和服务端库(net),HTTP库(HTTP和HTTPS)、域名解析库(DNS)、还有一个用来写测试的断言库(assert)、以及一个用于查询平台信息的操作糸统库(os)。
调试器:node自带了调试器,只需要带着
--debug
参数去运行程序就可以开启调试器。三种主流的node程序:web app,命令行工具,后台程序、桌面程序。
node编程基础
node项目分组传统的方式是按照逻辑相关性,将包含大量代码的单个文件分解成多个文件。
在node中,模块打包代码是为了重用,但他们不会改变全局作用域。
node模块允许从被引用文件中选择要暴露给程序的函数和变量。如果模块返回的函数或变量不止一个,那可以通过设定
exports对象
的属性来指明它们。但如果模块只是返回一个函数或变量,则可以设定module.exports属性。node的模块系统避免了对全局作用域的污染,从而避免了命名冲突,简化了代码的重用。
NODE WEB 程序
- 组成部分:
package.json:一个包含依赖项列表和运行这个程序的命令的文件
public:静态资源文件夹,CSS和客户端JS都放在这里
node_modules:项目的依赖项
方程序代码的一个或多个JS文件
程序代码分为几块
app.js或者index.js,设置程序的代码
models,数据库模型
views,用来渲染页面的模板
controllers或routes,HTTP请求处理器
middleware,中间组件
项目:later
- npm init -fy
- 使用http模块需要做很多套路化的开发工作,我们使用便捷的Express。
cnpm install --save express
- 卸载express
npm rm express -save
- npm脚本:就是以scripts的字段的npm命令,可以代替
node index.js
这样的命令。 - PHP程序是页面,NODE程序是服务器。
- 添加RESTful路由,所谓的RESTful路由就是帮我们确定程序的API,以及需要哪些数据库模型。
- RESTful API就是REST风格的网络接口,REST描述的是在网络中client和server的一种交互形式;REST本身不实用,实用的是如何设计。
- 设计RESTful服务时,要想好需要哪些操作,并将它们映射到EXPRESS里的路由上。我们这里需要实现的有:保存文章、获取文章、获取包含所有文章的列表和删除不再需要的文章,总共四个功能:对应以下的路由:
POST /article 创建新文章, RESTful路由示例不能创建文章,因为POST请求需要消息体解析器。
GET /article/:id 获取指定文章
GET /articles 获取所有文章
DELETE /articles/:id 删除指定文章 - 在考虑数据库和web界面等问题之前,我们先重点解决如何用EXPRESS创建RESTful资源的问题。可以使用CURL向示例程序发起请求,然后再逐步实现数据存储等更加复杂的操作,让程序编程一个真正的web程序。
- 使用express程序实现上面的路由,但现在使用JS数组来存储文章。RESTful路有示例
10.使用cURL向程序发起请求:
获取一篇文章:curl localhost:3000/articles/0
获取所有文章:curl localhost:3000/articles
删除一篇文章:curl -x DELETE localhost:3000/articles/0
- 消息体解析器知道如何接受MIME-encoded(多用途互联网邮件扩展)POST请求消息的主题部分,并将其转换成代码可用的数据。一般来说它给出的是易于处理的JSON数据。
cnpm install --save body-parser
- 到此已经是完成了RESTful的路由,还需要做两件事:将数据永久保存在数据库中,第二个任务是为找到的文章生成一个可读版本。
- 添加数据库:为node程序添加数据库没有必须的规定,但一般都涉及几个步骤:
1.决定要用的数据库系统 =》
2.在NPM上找那些实现了数据库驱动或对象-关系映射(ORM)的热门模块 =》
3.用npm –save将模块添加到项目中 =》
4.创建模型,封装数据库访问API =》
5.把这些模型添加到Express路由中 - 使用SQLite,它是一个进程内数据库,不需要在系统中安装一个后台运行的数据库,添加的所有数据都会写到一个文件里,程序停止后数据还在。
- 制作自己的数据库模型API:文章应该能被创建、获取、删除
Article.all(cb) 返回所有文章
Article.find(id, cb) 给定ID找对应文章
Article.create({title, content}, cb) 创建一篇有标题和内容的文章
Article.delete(id, cb) 根据ID 删除文章 - RESTful API搭建好了,数据也可以持久化到数据库中,接下来就是需要写代码把网页转换成简化版的“阅读视图”了。
- 现在我们的程序已经可以保存文章了,也可以获取他们,为了能够阅读这些文章,我们需要添加WEB界面。给EXPRESS项目添加界面需要做几件事:首先需要使用模板引擎。程序眼需要服务静态文件,比如CSS。如何在必要时让前面的例子中的路由处理器同时支持JSON和HTML响应。
- 支持多种格式:同时支持HTML和JSON格式,使用Express的res.fromat方法,可以根据请求发送响应的响应。
- 渲染模板,使用ESJ模板。
- 响应静态文件请求,EXPRESS有一个express.static的中间件,可以给浏览器发送JS、图片和CSS文件。只要将它指向包含这些文件的目录,浏览器就能访问这些文件。
Node的web开发
- 用npm脚本简化复杂的命令
在项目的package.json文件,有scripts属性。可以在那里指定自己的命令。 - 用Gulp管理重复性任务
前端自动化构建:Gulp,提供JavaScript API以实现自动化构建
Gulp是一个通用的项目自动化工具。它适合管理项目里的跨平台清理脚
本,比如运行复杂的客户端测试或者为数据库提供固定的测试环境. - 用Webpack打包客户端web程序
Webpack是专门用来构建Web程序的.比如说,你要跟一位设计师合
作,他已经给一个单页Web程序创建了静态站,而你要改写它,构建更
高效的CSS和ES2015 JavaScript代码。
Webpack的优势之一是更容易快速搭建出一个支持增量式构建的构建系
统。
CONNECT
- 如何用中间件搭建简单的Web程序
Connect中间件就是JavaScript函数,这个函数一般会有三个参数:请求对象、响应对象,以及一个名为next 的回调函数。
Connect中的use 方法就是用来组合中间件的
一个有next ,一个没有。因为后面这个中间件完成了HTTP响应,再也不需要把控制权交还给分派器了。
use() 函数返回的是Connect程序的实例,支持方法链 中间件的顺序的重要性
为什么.use() 的调用顺序很重要,以及如何策略地用这个顺序调整程序的工作方式。
没有调用next() ,所以控制权没有交回给分派器,它也不能调用下一个中间件
也就是说,如果某个中间件不调用next() ,那链在它后面的中间件就不会被调用。创建可配置的中间件
1
2
3
4
5
6
7
8function setup(options) {
// 设置逻辑
←---- 在这里做中间件的初始化
return function(req, res, next) {
// 中间件逻辑
←---- 即使被外部函数返回了,仍然可以访问options
}
}错误处理
connect有默认处理器,也可以自行处理。
错误处理中间件函数必须有四个参数:err 、req 、res 和next(常规的中间件只有req,res和next三个参数。) 当Connect遇到错误时,它会切换,只去调用错误处理中间件
1 | connect() |
例子:在开发中用简单快捷的错误报告,比如JSON格式发送错误;在生产环境中不把敏感信息(比如栈跟踪、文件名)暴露给攻击者,只发送一个简单的服务器错误响应。
用NODE_ENV(process.env.NODE_ENV)设定程序的模式,用这个属性切换不同服务器环境。
Express
生成程序;
express-generator包里有创建程序框架的命令行工具express(1)express -e shoutbox
探索生成的程序:
dirname:
Node中的 dirname (前面有两个下划线)是个全局变量,表示当前运行的文件所在的目录
morgan:
用于node.js的HTTP请求记录器中间件
http-errors:
轻松地为Express、Koa、Connect等创建HTTP错误。
cookie-parser:
解析Cookie头并填充req.cookie的对象由cookie的名称键入。
app.locals:
app.locals:
对象的属性是应用程序中的局部变量。一旦设置,app.locals:
属性的值将在应用程序的整个生命周期中持续存在,而res.locals属性只对请求的生命周期有效。
res.locals:
一个对象,其中包含作用域为请求的响应局部变量,因此仅可用于请求/响应周期期间呈现的视图(如果有)。否则,该属性与app.locals相同。
app.set:
分配设置name给value。您可以存储您想要的任何值,但某些名称可用于配置服务器的行为
express.route:
创建一个新的路由器对象。您可以添加中间件和HTTP方法路由(如get,put,post,等),以router就像一个应用程序。
EXPRESS和程序的配置
配置特定环境以及程序层面的配置项:比如用的是什么模板引擎,到哪里去找模板
设置环境变量:
UNIX:
NODE_ENV=production
WINDOW:
set NODE_ENV=production
这些环境变量会出现在程序里的process.env 对象中。
环境驱动配置系统:
app.set()
app.get()
app.enable() 等同于 app.set(setting, true)
app.disable()
app.enabled() 用来检查该值是否被启用了
app.disabled()
基于环境的配置
渲染视图
概念:把数据传给视图,视图对数据进行转换。对Web程序来说,通常是转换成HTML。
Express中有两种渲染视图的办法:程序层面用app.render() ,在请求
或响应层面用res.render() ,Express内部用的是前一种。
配置视图系统
调整视图的查找;
设定views目录:app.set('views', path.join(__dirname, 'views'))
配置默认的模板引擎;
Express要靠扩展名确定用哪个模板引擎渲染文件,但有了这个配置项,我们可以用index 指定要渲染的文件,而不需要用index.ejs 。在命令行中用 -e 指定模板引擎EJS,所以view engine 被设为ejs
Express为什么还要考虑扩展名。
因为如果使用带扩展名的模板文件,就可以在同一个Express程序中使用多个模板引擎。1
2
3
4
5
6
7
8// 默认引擎是Pug
app.set('view engine', 'pug');
app.get('/', function(){
res.render('index');
});
app.get('/feed', function(){
res.render('rss.ejs');
});
启用视图缓存,减少文件I/O。
在生产环境中,view cache (视图模板编译缓存)是默认开启的,以防止后续的render() 从硬盘中读取模板文件.因为模板文件中的内容会被放到内存中,所以性能会得到显著提升.但启用这个配置项后,只有重启服务器才能让模板文件的编辑生效,所以在开发时会禁用它。
https://segmentfault.com/img/bVblOaH
视图查找
查找视图的过程跟require() 查找模块的过程差不多。
view lookup 可以帮我们组织这些视图,比如说把视图文件放在跟资源相连的子目录中.
用添加子目录的办法可以去掉模板文件名称中的冗余部分,比如edit-entry.ejs和show-entry.ejs。Express会添加跟view engine 匹配的扩展名,根据res.render(‘entries/edit’) 定位到
./views/entries/edit.ejs。
当文件的名称为复数时,比如entries,通常表示这是一个资源列表。也就是说res.render(‘entries’) 一般会渲染文件views/entries/index.ejs。
将数据传递给视图的办法
- 作为res.render()的参数,最常用
- 在路由处理器之前的中间件中设定一些变量,比如app.locals传递程序层面的数据,用res.locals传递请求层面的数据。
- 将变量直接作为res.render() 的参数优先级最高,要高于在res.locals 和app.locals 中设定的变量值
- 默认情况下,Express只会向视图中传递一个程序级变量——
settings,这个对象中包含所有用app.set() 设定的值。比如app.set(‘title’, ‘My Application’) 会把settings.title输出到模板中,请看下面的EJS代码片段:
EXPRESS路由入门
Express路由的主要任务是将特定模式的URL匹配到响应逻辑上。也可以将URL模式匹配到中间件上,以便用中间件实现某些路由上的可重用功能。
- 用特定路由的中间件校验用户提交的内容;
为了介绍校验的做法,要给程序加上消息提交的功能。
- 创建消息模型
- 实现特定路由的校验。
使用MongoDB
- 大部分数据库都是通过collection API完成的